export default class AStarTool {
    private m_openList = [];
    private m_closeList = [];
    private m_grids = null;

    private m_beginPos: cc.Vec2 = null;
    private m_endPos: cc.Vec2 = null;

    private m_endNode = null;
    private m_blockFlags = [];

    constructor(){
        this.m_openList = [];
        this.m_closeList = [];
        this.m_grids = null;
    }

    public init(blockFlags: number[]){
        this.m_blockFlags = blockFlags;
    }

    getPath(grids, beginPos, endPos){
        if(beginPos.equals(endPos)) return null;

        this.m_grids = grids;
        this.m_beginPos = beginPos;
        this.m_endPos = endPos;
        this.m_openList = [];
        this.m_closeList = [];
        this.m_endNode = null;

        var checkPos = beginPos;
        var checkNode = this.addOpenList(checkPos, null);
        var nextPos = new cc.Vec2(checkPos.x - 1, checkPos.y);
        if(this.checkCanPass(nextPos) && !this.isInCloseList(nextPos)){
            this.addOpenList(nextPos, checkNode);
        }
        nextPos = new cc.Vec2(checkPos.x + 1, checkPos.y);
        if(this.checkCanPass(nextPos) && !this.isInCloseList(nextPos)){
            this.addOpenList(nextPos, checkNode);
        }
        nextPos = new cc.Vec2(checkPos.x, checkPos.y + 1);
        if(this.checkCanPass(nextPos) && !this.isInCloseList(nextPos)){
            this.addOpenList(nextPos, checkNode);
        }
        nextPos = new cc.Vec2(checkPos.x, checkPos.y - 1);
        if(this.checkCanPass(nextPos) && !this.isInCloseList(nextPos)){
            this.addOpenList(nextPos, checkNode);
        }
        this.removeOpenList(checkPos);

        while(this.m_endNode == null && this.m_openList.length > 0){
            checkNode = this.getCheckNode();
            checkPos = checkNode.pos;
            this.removeOpenList(checkPos);
            
            var nextPos = new cc.Vec2(checkPos.x - 1, checkPos.y);
            if(this.checkCanPass(nextPos) && !this.isInCloseList(nextPos)){
                this.addOpenList(nextPos, checkNode);
            }
            nextPos = new cc.Vec2(checkPos.x + 1, checkPos.y);
            if(this.checkCanPass(nextPos) && !this.isInCloseList(nextPos)){
                this.addOpenList(nextPos, checkNode);
            }
            nextPos = new cc.Vec2(checkPos.x, checkPos.y + 1);
            if(this.checkCanPass(nextPos) && !this.isInCloseList(nextPos)){
                this.addOpenList(nextPos, checkNode);
            }
            nextPos = new cc.Vec2(checkPos.x, checkPos.y - 1);
            if(this.checkCanPass(nextPos) && !this.isInCloseList(nextPos)){
                this.addOpenList(nextPos, checkNode);
            }
        }

        if(this.m_endNode != null){
            var result = [];
            result.push(this.m_endNode.pos);

            var parent = this.m_endNode.parent;
            while(parent != null){
                result.push(parent.pos);

                parent = parent.parent;
            }
            return result;
        }else{
            return null;
        }
    }

    checkCanPass(pos){
        return pos.x >= 0 && pos.y >= 0 && this.m_grids[pos.x] != null && this.m_grids[pos.x][pos.y] != null && this.m_blockFlags.indexOf(this.m_grids[pos.x][pos.y]) == -1;
    }

    addOpenList(pos, parent){
        var node = this.getNodeFromOpenList(pos);
        if(node != null && parent != null){
            var _g = parent.g + (Math.abs(pos.x - parent.pos.x) + Math.abs(pos.y - parent.pos.y)) == 2 ? 14 : 10;
            if(_g < node.g){
                //更优
                node.parent = parent;
                node.g = _g;
                node.f = node.h + node.g;
            }
        }else{
            node = {
                pos: pos,
                parent: parent,
                g: 0,
                h: 0,
                f: 0,
            }
        
            if(parent != null){
                node.g = parent.g + (Math.abs(pos.x - parent.pos.x) + Math.abs(pos.y - parent.pos.y)) == 2 ? 14 : 10;
            }

            node.h = (Math.abs(this.m_endPos.x - pos.x) + Math.abs(this.m_endPos.y - pos.y)) * 10;
            node.f = node.h + node.g;

            this.m_openList.push(node);

            if(pos.equals(this.m_endPos)){
                this.m_endNode = node;
            }
        }
            

        return node;
    }

    removeOpenList(pos){
        for(var i = 0; i < this.m_openList.length; i++){
            if(this.m_openList[i].pos.equals(pos)){
                this.m_closeList.push(this.m_openList[i]);
                this.m_openList.splice(i, 1);
                break;
            }
        }
    }
    
    getCheckNode(){
        var minF = Number.MAX_VALUE;
        var result = null;

        this.m_openList.forEach(node=>{
            //找F最小
            if(node.f < minF){
                minF = node.f;
                result = node;
            }
        });

        return result;
    }

    getNodeFromOpenList(pos){
        for(var i = 0; i < this.m_openList.length; i++){
            if(this.m_openList[i].pos.equals(pos)){
                return this.m_openList[i];
            }
        }
        return null;
    }

    isInCloseList(pos){
        for(var i = 0; i < this.m_closeList.length; i++){
            if(this.m_closeList[i].pos.equals(pos)){
                return true;
            }
        }
        return false;
    }
}